Skip to content

With package.json "exports" resolve paths deeply with conditional rules #3993

Closed as not planned
@alshdavid

Description

@alshdavid

Details

I am trying to use the exports in my package.json to deeply resolve module paths on top of a base path.

Essentially I have this folder structure:

./my-pkg
└── dist
   └── cjs
      ├── foo
      │  ├── bar
      │  │  └── index.js
      │  └── index.js
      └── index.js

And I would like node to be able to resolve the paths above as if they were /

console.log(require('my-pkg'))          // my-pkg/dist/cjs/index.js
console.log(require('my-pkg/foo'))      // my-pkg/dist/cjs/foo/index.js
console.log(require('my-pkg/foo/bar'))  // my-pkg/dist/cjs/foo/bar/index.js

The basic implementation of exports works for resolving the top level files (except the types keyword isn't being picked up by TypeScript 4.7, but that's another battle for another day):

{
  "exports": {
    ".": {
      "types": "./dist/types/index.d.ts",
      "import": "./dist/esm/index.js",
      "require": "./dist/cjs/index.js"
    }
  },
  ...
}

This allows me to import the following without issue

console.log(require('my-pkg'))  // my-pkg/dist/cjs/index.js

In the Node documentation it describes using * to add conditional resolution:

{
  ".": {
    "types": "./dist/types/index.d.ts",
    "import": "./dist/esm/index.js",
    "require": "./dist/cjs/index.js"
  },
  "./*": {
    "types": "./dist/types/*/index.d.ts",
    "import": "./dist/esm/*/index.js",
    "require": "./dist/cjs/*/index.js"
  }
},
console.log(require('my-pkg'))          // works
console.log(require('my-pkg/foo'))      // works
console.log(require('my-pkg/foo/bar'))  // does not work

This doesn't allow paths nested beyond ./*/. I have experimented with glob patterns like below but had no luck

{
  ".": {
    "types": "./dist/types/index.d.ts",
    "import": "./dist/esm/index.js",
    "require": "./dist/cjs/index.js"
  },
  "./**/*": {
    "types": "./dist/types/**/*",
    "import": "./dist/esm/**/*",
    "require": "./dist/cjs/**/*"
  }
},

I could explicitly add each nested path into exports manually but I would much prefer deep folder/file resolution be handled by node directly.

Any idea what I need to do to get this working?

Node.js version

Not applicable.

Example code

No response

Operating system

All

Scope

Module resolution

Module and version

Not applicable.

Activity

changed the title With package.json "exports", is there a conditional rule to allow resolving paths deeply? With package.json "exports" resolve paths deeply with conditional rules on Feb 17, 2023
gabzim

gabzim commented on Sep 24, 2023

@gabzim

Any help with this? having the same issue

ljharb

ljharb commented on Sep 24, 2023

@ljharb
SponsorMember

There is no solution besides doing it manually, for each level of nesting, i believe.

alshdavid

alshdavid commented on Sep 29, 2023

@alshdavid
Author

This (mostly) works:

{
  "name": "pkg",
  "exports": {
    "./": {
      "import": "./import/index.js",
      "require": "./require/index.js"
    },
    "./*": {
      "import": "./import/*",
      "require": ["./require/*", "./require/*.js", "./require/*/index.js"]
    }
  }
}

So from a CJS context:

const pkg = require('pkg')             /** resolves to */ 'node_modules/pkg/require/index.js'

const pkg = require('pkg/index')       /** resolves to */ 'node_modules/pkg/require/index'   
                                                /** or */ 'node_modules/pkg/require/index.js'
                                                /** or */ 'node_modules/pkg/require/index/index.js'

const pkg = require('pkg/index.js')    /** resolves to */ 'node_modules/pkg/require/index.js'

const pkg = require('pkg/foo.js')      /** resolves to */ 'node_modules/pkg/require/foo.js'

const pkg = require('pkg/foo')         /** resolves to */ 'node_modules/pkg/require/foo'    
                                                /** or */ 'node_modules/pkg/require/foo.js'
                                                /** or */ 'node_modules/pkg/require/foo/index.js'

const pkg = require('pkg/foo/bar')     /** resolves to */ 'node_modules/pkg/require/foo/bar' 
                                                /** or */ 'node_modules/pkg/require/foo/bar.js'
                                                /** or */ 'node_modules/pkg/require/foo/bar/index.js'

const pkg = require('pkg/foo/bar.js')  /** resolves to */ 'node_modules/pkg/require/foo/bar.js'

And from a MJS context:

import pkg from 'pkg'               /** resolves to */ 'node_modules/pkg/import/index.js'
import pkg from 'pkg/index'         /** not valid, requires extension */
import pkg from 'pkg/index.js'      /** resolves to */ 'node_modules/pkg/import/index.js'
import pkg from 'pkg/foo.js'        /** resolves to */ 'node_modules/pkg/import/foo.js'
import pkg from 'pkg/foo'           /** not valid, requires extension */
import pkg from 'pkg/foo/bar.js'    /** resolves to */ 'node_modules/pkg/import/foo/bar.js'

However Node accepts but only resolves the first item in an Array when supplied as a subpattern export.

I have raised a bug report to hopefully change that nodejs/node#49945

If that is updated, then the package.json config above will work as expected for nested patterns.

alshdavid

alshdavid commented on Sep 29, 2023

@alshdavid
Author

looks like there is a discussion on this here: nodejs/node#37928

github-actions

github-actions commented on May 7, 2024

@github-actions

It seems there has been no activity on this issue for a while, and it is being closed in 30 days. If you believe this issue should remain open, please leave a comment.
If you need further assistance or have questions, you can also search for similar issues on Stack Overflow.
Make sure to look at the README file for the most updated links.

github-actions

github-actions commented on Jun 7, 2024

@github-actions

It seems there has been no activity on this issue for a while, and it is being closed. If you believe this issue should remain open, please leave a comment.
If you need further assistance or have questions, you can also search for similar issues on Stack Overflow.
Make sure to look at the README file for the most updated links.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

      Participants

      @ljharb@gabzim@alshdavid@preveen-stack

      Issue actions

        With package.json "exports" resolve paths deeply with conditional rules · Issue #3993 · nodejs/help